package ink.xieyu.utils.scan;

import ink.xieyu.annotation.CommonBeanBuilderAnnotation;
import ink.xieyu.ex.BeanBuilderException;
import ink.xieyu.utils.charutils.StringUtil;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用于搜寻bean的工具
 */
public class SeekBeanUtil {
    private List<Class<?>> classes;
    /**
     * bean对象map
     * key bean名称 value 生成的bean
     */
    private Map<String, Object> beanByName = new HashMap<>();
    /**
     * bean对象map
     * key bean类型 value 生成的bean
     */
    private Map<String, Object> beanByType = new HashMap<>();

    public SeekBeanUtil(List<Class<?>> classes) throws BeanBuilderException {
        this.classes = classes;
        scanBean();
        System.err.println(beanByName);
    }



    /**
     * 扫描所有携带CommonBeanBuilderAnnotation注解或其子类，并且加载对象
     * todo 目前只能支持无参构造 如果有参构造函数暂不支持
     */
    private void scanBean() throws BeanBuilderException {
        AnnotationScanUtil annotationScanUtil=new AnnotationScanUtil();
        for (Class<?> value : classes) {
            CommonBeanBuilderAnnotation annotation = annotationScanUtil.doBeanScan(value);
            if (annotation != null) {
                Object bean = loadBean(value);
                beanByName.put(getBeanName(annotation, value), bean);
                beanByType.put(value.getSimpleName(), bean);
            }
        }

    }

    /**
     * 加载bean
     * todo 暂时只支持无参构造参数
     *
     * @param clazz
     * @return 返回生成的bean
     */
    private Object loadBean(Class<?> clazz) throws BeanBuilderException {
        Constructor<?> constructors;
        try {
            constructors = clazz.getConstructor();
            return constructors.newInstance();
        } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) {

            throw new BeanBuilderException(clazz.getName() + "没有无参构造参数!", e);
        }
    }

    /**
     * 获取bean名称,如果bean名称为空,则为类名首字母小写。
     *
     * @param commonBeanBuilderAnnotation
     * @return
     */
    private String getBeanName(CommonBeanBuilderAnnotation commonBeanBuilderAnnotation, Class<?> clazz) {
        return StringUtil.isBlank(commonBeanBuilderAnnotation.value()) ? StringUtil
                .littleHump(clazz.getSimpleName()) : commonBeanBuilderAnnotation.value();
    }

    /**
     * @param clazz 获取的bean
     * @param flag  是否必须 如果为true则需要加载
     * @return
     */
    public Object getBean(Class<?> clazz, String beanName, boolean flag) throws BeanBuilderException {
        if (!flag) {
            return null;
        }
        Object bean = beanByName.get(beanName);
        if (bean != null) {
            return bean;
        }
        bean = beanByType.get(clazz.getSimpleName());
        if (bean != null) {
            return bean;
        }
        throw new BeanBuilderException("找不到bean异常!");
    }
}
